//server.h
#ifndef SERVER_H
#define SERVER_H

#include "list.h"
#include "synch.h"
#include <map>
#include <list>
#include <time.h>

#define MAX_MV_LENGTH 128
#define MAX_SERVER_MV 256
#define MAX_SERVER_LOCKS 256
#define MAX_SERVER_CONDS 256

//An Explanation:
// I store the id and boxes as wait queues rather than the reply message
// simply because each message in the queue has at least 32 bytes of data
// that are identical every time. The message can be generated before sending
// using just these 16 bytes of data, thus saving space

class Client{
public:
	int machineID;
	int boxID;
	
	Client(int machine, int box)
	{
		machineID=machine;
		boxID=box;
	}
};

struct cmp_client
{
   bool operator()(Client const a, Client const b)
   {
	return (a.machineID<b.machineID&&a.boxID<b.boxID);
      //return std::strcmp(a, b) < 0;
   }
};

class ServerLock{
public:
	bool available;
	int ownerID; 		//machine id
	int ownerBox;		//mailbox id
	List* idQ;
	List* boxQ;
	char* name;
	
	ServerLock(char* str);
	~ServerLock();
	void Acquire(int id, int box);
	void Release(int id, int box);
};

//NOTE TO SELF:
// Don't send replies from the conditions,
// have threads wait instead to hear they've
// acquired the relevant lock after the Signal
class ServerCondition{
public:
	std::list<int> * idQ;
	std::list<int> * boxQ;
	int lockUsed;
	bool inUse;
	char* name;
	
	ServerCondition(char* str);
	~ServerCondition();
	void Wait(int id, int box, int lockNum);
	void Signal(int lockNum);
	void Broadcast(int lockNum);
};

class ServerMV{
public:
	int* data;
	int numRows;
	int numCols;
	char* name;
	
	ServerMV(int rows, int cols, char* name);
	~ServerMV();
	void getValue(int r, int c, int id, int box);
	void setValue(int r, int c, int val);
};

//tables
ServerLock* serverLockTable[MAX_SERVER_LOCKS];
bool createdSL[MAX_SERVER_LOCKS];
bool destroySL[MAX_SERVER_LOCKS];
ServerCondition* serverCondTable[MAX_SERVER_CONDS];
bool createdSC[MAX_SERVER_CONDS];
bool destroySC[MAX_SERVER_CONDS];
ServerMV* serverMVTable[MAX_SERVER_MV];
bool createdMV[MAX_SERVER_MV];
bool destroyMV[MAX_SERVER_MV];
int nextAvailableSL = 0;
int nextAvailableSC = 0;
int nextAvailableMV = 0;
std::map<std::string,int> lockNameMap;
std::map<std::string,int> condNameMap;
std::map<std::string,int> MVNameMap;

//these are only used by create/destroy/DYH calls
Lock* lockTableLock;
Lock* condTableLock;
Lock* MVTableLock;

//Pinging variable
time_t lastPingTime;

//for communicating between primary and IST
//because of the waiting for replies, only replies of one type should be coming in
Lock* replyLock;
Condition* replyCond;
int repliesRemaining;
int queriesToSend;
int offServerID;
int serverList[5];
bool goodLock;

//functions
void RegisterWithBinder();
void ServerCreateLock(char* str, int index, int destID, int destBox);
void ServerCreateCondition(char* str, int index, int destID, int destBox);
void ServerCreateMV(int rows, int cols, int len, char* str, int index, int destID, int destBox);

void PingLockHolders();

void updateNSL();
void updateNSC();
void updateNMV();

void ServerMain();
void InterServerThread(int doesNothing);
void PingThread(int doesNothing);

#endif
